require 'rudoku'
include Rudoku

require 'rules'
require 'field_selectors'
require 'candidate_selectors'

$debug = false
$enable_color = true

class String
  def indent(margin)
    split("\n").collect { |l| (" " * margin) + l }.join("\n")
  end
end

# we reopen the RULE class to make aborting possible
class Rule
  alias :apply_to_old :apply_to
  
  def apply_to(sudoku)
    eliminations = apply_to_old(sudoku)
        
    solved_before = sudoku.solved_fields.size
    eliminations.each { |e| e.perform } # ALREADY PERFORM THE ELIMINATIONS! the Solver will do this again, but it will have no effect.
    solved_after = sudoku.solved_fields.size
    solved_diff = solved_after - solved_before
    
    puts ">> \e[32mAPPLIED\e[0m #{name}"
    
    if sudoku.changed?
      puts "   Constraints changed"
      if solved_diff > 0
        puts "   #{solved_diff} additional fields were solved"
        puts "\n"
        puts sudoku.to_s.indent(8)
        puts "\n"
        puts (" " * 8) + "#{solved_after} solved fields\n\n"
      else
        puts "\n\n"
      end
    else
      puts "   No constraint changes\n\n"
    end
    
    puts ">> \e[1;31mINCONSISTENCY DETECTED!\e[0m BACKTRACKING!\n\n" unless sudoku.consistent?
    
    puts ">> (C)ontinue, (A)bort?"
    proceed = gets.chomp
    puts "\n"
    
    if proceed.upcase == "A"
      puts ">> \e[31mABORTING\e[0m solving process"
      throw :user_abort
    end
    
    eliminations
  end
end

class Solver
  alias :guess_and_solve_old :guess_and_solve
  
  def guess_and_solve(sudoku)
    puts ">> \e[1;33mGUESSING\e[0m a value, rules are exhausted!\n\n"
    guess_and_solve_old(sudoku)
  end
end

metro = "--38----4-7--5461-2----7-5-9-532-7------8593-6--49----7--6---8--26-1----4-----1-2"
manna_symmetrisch = "7-42-13-5---------3--5-7--26-5---8-3----7----4-3---9-72--9-5--1---------5-97-36-4"
manna_tiseenacht = "2--81--46---6--1--1-7----2-------261-2-9-3-5-654-------1----6-4--3--6---48--79--5"
qassim_hamza = "---7--8------4--3------9--16--5------1--3--4---5--1--75--2--6---3--8--9---7-----2"
jf1 = "100000002090400050006000700050903000000070000000850040700000600030009080002000001" # this is the Easter Monster
jf3 = "708000300000201000500000000040000026300080000000100090090600004000070500000000000"


sudoku = Sudoku.from_str manna_symmetrisch
solver = Solver.new [HiddenSingle, DirectElimination, LockedCandidatesPointing, NakedPair, XWing, Swordfish], UberFieldSelector, UberCandidateSelector

puts "\n--------- \e[1;32mRUDOKU\e[0m STEP-BY-STEP SOLVER ---------\n\n\n"
puts ">> \e[1;33mUNSOLVED GRID\e[0m\n\n"
puts sudoku.to_s.indent(8)
puts "\n\n"

catch(:user_abort) { solver.solve(sudoku, true) }

if sudoku.solved?
  puts ">> \e[1;32m SOLVED!\e[0m"
else
  puts ">> \e[1;31m FAILED\e[0m to solve sudoku :("
end


=begin

=end
